🔷 При решении ноутбука используйте данный шаблон
✅ Можно добавлять новые ячейки любых типов
❌ Не нужно удалять текстовые ячейки c разметкой частей ноутбука и формулировками заданий
🔷 При оценивании задач учитывается код
✅ Задания, в которых необходим код, обычно помечаются фразами "Your code here"/"Ваш код" и аналогичными
❌ Ответы на вопросы без сопутствующего кода оцениваются в 0 баллов
❌ Наличе работоспособного кода в ноутбуке, если на сказано иного, обязательно
🔷 При оценивании задач учитываются выводы
✅ Задания, в которых необходимы выводы, обычно помечаются фразами Вывод"/"Ответ на вопрос"/"Ваш текст" и аналогичными
✅ Обычно выводы подразумевают под собой текстовый ответ (можно писать markdown, latex).
✅ Сопутствующие изображения, графики, таблички - приветствуются!
❌ При отсутствии выводов задание не засчитается на полный балл
Цель данного задания:
**Примерное время выполнения (execution time/время выполнения, если нажать run all) всех ячеек ноутбука при правильной реализации: до 10 минут **
Сначала установим нужные нам версии библиотек. Мы гарантируем, что в данных версиях задание будет корректно отрабатывать.
После установки нужных версий, возможно, нужно перезагрузить среду (runtime), но скорее всего вам это не понадобится
На скачивание файла и установку понадобится не более 5 минут.
**Важно!**
Устанавливать нужные версии нужно каждый раз, когда создается новый рантайм. Например, если вы 2 часа подряд делаете это задание, то подготовить библиотеки достаточно 1 раз. Но если вы, например, начали в понедельник, затем закрыли/выключили ноутбук, то при продолжении в среду, вам нужно будет запустить рантайм заново и следовательно заново установить библиотеки.
**Важно!** Если вы предпочитаете делать практические задания на своем личном ноутбуке, то проверьте, что вы установили рабочее окружение в соответствии с гайдом.pdf)
! curl https://raw.githubusercontent.com/MSU-ML-COURSE/ML-COURSE-25-26/refs/heads/master/requirements/requirements.txt -o ./requirements_2025_26_for_colab_small.txt
! pip install -q -r ./requirements_2025_26_for_colab_small.txt
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 360 100 360 0 0 1819 0 --:--:-- --:--:-- --:--:-- 1827
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.0/62.0 kB 2.7 MB/s eta 0:00:00
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 99.2/99.2 MB 8.7 MB/s eta 0:00:00
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.9/4.9 MB 73.8 MB/s eta 0:00:00
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 515.7/515.7 kB 26.9 MB/s eta 0:00:00
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 41.5/41.5 kB 2.2 MB/s eta 0:00:00
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 365.5/365.5 kB 23.7 MB/s eta 0:00:00
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 35.2/35.2 MB 50.4 MB/s eta 0:00:00
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 94.9/94.9 MB 8.5 MB/s eta 0:00:00
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.6/1.6 MB 58.6 MB/s eta 0:00:00
Проверим версию библиотеки:
import catboost
assert(catboost.__version__ == '1.2.8')
Теперь можно приступать к выполнению задания! :)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
from copy import copy
Если Вы дальтоник, то можете воспользоваться готовой colormap из matplotlib (или найти свою):
plt.style.use('tableau-colorblind10')
Приведем вспомогательный код
from matplotlib.colors import ListedColormap
from sklearn.svm import LinearSVC, SVC
from sklearn.decomposition import PCA
from sklearn.model_selection import cross_val_score, cross_val_predict, cross_validate, train_test_split
from sklearn.metrics import make_scorer, accuracy_score, roc_auc_score
from sklearn.datasets import make_blobs, make_circles, make_moons
def make_moons_cls(size=1000, d=2):
X, y = make_moons(n_samples=size, noise=0.15)
if d > 2:
X = np.concatenate((X, np.random.normal(size=(size, d-2))), axis=1)
return X, y
def make_circles_cls():
X, y = make_circles()
def generate_data_with_imb_classes(size1=100, size2=10):
X = np.r_[(
np.random.normal(loc=1.0, size=(size1, 2)),
np.random.normal(loc=0.5, size=(size2, 2))
)]
y = np.ones(len(X))
y[-size2:] = 0
return X, y
def plot_separating_surface(X, y, cls, view_support=False, title=''):
x_min = min(X[:, 0]) - 0.1
x_max = max(X[:, 0]) + 0.1
y_min = min(X[:, 1]) - 0.1
y_max = max(X[:, 1]) + 0.1
h = 0.005
cm = plt.cm.RdBu
cm_bright = ListedColormap(['#FF0000', '#0000FF'])
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = cls.predict(np.c_[xx.ravel(), yy.ravel()])
plt.figure(figsize=(10, 10))
if title:
plt.title(title)
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', s=40, cmap=cm_bright)
if view_support:
plt.scatter(X[cls.support_, 0], X[cls.support_, 1],
c=y[cls.support_], edgecolors='k', s=150, cmap=cm_bright)
Z = Z.reshape(xx.shape)
plt.xticks(())
plt.yticks(())
plt.contourf(xx, yy, Z, cmap=cm, alpha=.3)
plt.show()
import gdown
gdown.download_folder('https://drive.google.com/drive/folders/1bp39_Jj0edo1lzxZ3DIoChsOVy5DVi1R?usp=sharing')
Retrieving folder contents
Retrieving folder 1tv605hGxdQtd4zC787DbcRF0312gDeK_ imbalanced Processing file 14zd2xHDChSHtMWQ_TUzM8td7s8gzCO2u X_imb_test.npz.npy Processing file 1Qed066d3gUsUOZiUZu6aCrIH9f0yWKSc X_imb.npz.npy Processing file 1uD87Xbh4MMBBn5fsScrknI54SINIqory y_imb_test.npz.npy Processing file 1RR2VU_6WJMLo88k8C1VzBwb2Ibnz1yJf y_imb.npz.npy Retrieving folder 1uoI6vZWwIII1jd2k5TtsZTJ3JOkK0G6O public Processing file 1Win7ZtHLHEbDtX6x6O7vBJHwJviQxbp5 cX_test.npy Processing file 1MowPnLFAMEjjcAjDA4skE4OUFdmaiSY6 cX_train.npy Processing file 1VYA4N5wCQhwteQSZkDogFTha2xRv0FgW cy_train.npy
Retrieving folder contents completed Building directory structure Building directory structure completed Downloading... From: https://drive.google.com/uc?id=14zd2xHDChSHtMWQ_TUzM8td7s8gzCO2u To: /content/05-SVM/imbalanced/X_imb_test.npz.npy 100%|██████████| 2.05k/2.05k [00:00<00:00, 1.69MB/s] Downloading... From: https://drive.google.com/uc?id=1Qed066d3gUsUOZiUZu6aCrIH9f0yWKSc To: /content/05-SVM/imbalanced/X_imb.npz.npy 100%|██████████| 2.05k/2.05k [00:00<00:00, 317kB/s] Downloading... From: https://drive.google.com/uc?id=1uD87Xbh4MMBBn5fsScrknI54SINIqory To: /content/05-SVM/imbalanced/y_imb_test.npz.npy 100%|██████████| 1.09k/1.09k [00:00<00:00, 3.71MB/s] Downloading... From: https://drive.google.com/uc?id=1RR2VU_6WJMLo88k8C1VzBwb2Ibnz1yJf To: /content/05-SVM/imbalanced/y_imb.npz.npy 100%|██████████| 1.09k/1.09k [00:00<00:00, 3.06MB/s] Downloading... From: https://drive.google.com/uc?id=1Win7ZtHLHEbDtX6x6O7vBJHwJviQxbp5 To: /content/05-SVM/public/cX_test.npy 100%|██████████| 8.13k/8.13k [00:00<00:00, 14.9MB/s] Downloading... From: https://drive.google.com/uc?id=1MowPnLFAMEjjcAjDA4skE4OUFdmaiSY6 To: /content/05-SVM/public/cX_train.npy 100%|██████████| 32.1k/32.1k [00:00<00:00, 44.7MB/s] Downloading... From: https://drive.google.com/uc?id=1VYA4N5wCQhwteQSZkDogFTha2xRv0FgW To: /content/05-SVM/public/cy_train.npy 100%|██████████| 6.53k/6.53k [00:00<00:00, 13.3MB/s] Download completed
['/content/05-SVM/imbalanced/X_imb_test.npz.npy', '/content/05-SVM/imbalanced/X_imb.npz.npy', '/content/05-SVM/imbalanced/y_imb_test.npz.npy', '/content/05-SVM/imbalanced/y_imb.npz.npy', '/content/05-SVM/public/cX_test.npy', '/content/05-SVM/public/cX_train.npy', '/content/05-SVM/public/cy_train.npy']
На лекции вы изучили, что линейная, с виду, модель SVM, при помощи некоторых "фокусов", называемых ядрами, умеет строить нелинейные поверхности. В данном ноутбуке посмотрим, как это все работает на практике, и какие гиперпараметры настройки у этого метода есть.
**Историческая справка:** Метод опорных векторов (SVM) стал популярным в 90-х годах, особенно с 1995 года, благодаря своей эффективности в задачах классификации и способности обрабатывать высокоразмерные данные. Он также привлек внимание благодаря использованию ядровых функций, что позволяло решать нелинейные задачи. Однако с появлением более сложных методов, таких как глубокое обучение, и увеличением объема данных, SVM стал менее популярным, поскольку более современные алгоритмы демонстрировали лучшие результаты на больших наборах данных и обеспечивали более простую настройку.
В ячейке ниже генерируется выборка, состоящая из объектов двух классов. Каждый объект представлен двумя координатами, так что объекты этой выборки можно отобразить на плоскости, используя функцию scatter из библиотеки matplotlib.
В этом задании вам надо будет обучить линейную разделяющую поверхность с помощью sklearn.svm.SVC(kernel='linear'), а также нелинейную c rbf-ядром с помощью sklearn.svm.SVC(kernel='rbf'). Остальные параметры методов можете оставить дефолтными. Делить выборку на обучение и валидацию сейчас не требуется, так как нас будет пока интересовать только форма разделяющей кривой.
X, y = make_moons_cls()
linear_svc = SVC(kernel='linear')
nonlinear_svc = SVC(kernel='rbf')
Визуализируем выборку
plt.figure(figsize=(8, 6))
plt.scatter(X[y == 0, 0], X[y == 0, 1], label='y=0')
plt.scatter(X[y == 1, 0], X[y == 1, 1], label='y=1')
plt.xlabel('$x_0$')
plt.ylabel('$x_1$')
plt.legend()
plt.grid()
Обучите модели и визуализируйте разделяющую поверхность для обеих моделей с помощью функции plot_separating_surface(). Посчитайте точность (accuracy) на обучающей выборке для каждой из моделей.
# Your code here
linear_svc.fit(X, y)
print(f'Train Accuracy (linear): {accuracy_score(y, linear_svc.predict(X)):.3f}')
plot_separating_surface(X, y, linear_svc)
Train Accuracy (linear): 0.871
# Your code here
nonlinear_svc.fit(X, y)
print(f'Train Accuracy (non linear): {accuracy_score(y, nonlinear_svc.predict(X)):.3f}')
plot_separating_surface(X, y, nonlinear_svc)
Train Accuracy (non linear): 0.987
Сделайте вывод о получившихся результатах. Какая из моделей лучше подходит для данной выборки и почему?
**Ваши выводы тут:**
Нелинейная модель с rbf-ядром, очевидно, намного лучше предсказала модель из-за нелинейного характера объектов
Продолжаем работать с выборкой и моделями из первой части. Для линейной и rbf-моделей рассмотрим опорные объекты, полученные после обучения. Визуализировать их можно, используя функуцию plot_separating_surface с параметром vissupport=True. Достанем опорные объекты из обученной модели с помощью поля model.support.
plot_separating_surface(X, y, nonlinear_svc, view_support=True)
Обучим новые две модели SVC(kernel='rbf'), используя только опорные объекты построенные с помощью соответственно линейной (linear_svc) и нелинейной (nonlinear_svc) моделей из первой части.
# Учим модели только на опорных объектах
svc_on_linear_support = SVC(kernel='rbf').fit(X[linear_svc.support_, :], y[linear_svc.support_])
svc_on_rbf_support = SVC(kernel='rbf').fit(X[nonlinear_svc.support_, :], y[nonlinear_svc.support_])
plot_separating_surface(X, y, svc_on_linear_support)
plot_separating_surface(X, y, svc_on_rbf_support)
Сравните полученные разделяющие поверхности с нелинейной моделью (nonlinear_svc) из задания 1. Какая из поверхностей больше похожа на нелинейнную модель из первой части и почему, опишите в выводе.
**Ваши выводы тут:**
Вторая больше похожа на нелинейную модель из первой части. Линейная модель просто проводит две "полосы" там, где находятся опорные объекты каждого из классов. Нелинейная модель с помощью ядра более корректно разделяет поверхность даже с учетом искдючительно опорных объектов
Теперь обучим модель SVC(kernel='rbf'), используя все объекты кроме тех, что являлись опорными для нелинейной модели из первой части (nonlinear_svc) и сравним эту модель вместе с svc_on_rbf_support с нелинейной моделью из задания 1(nonlinear_svc). Визуализируйте разделяющие поверхности обеих моделей.
non_support_vectors = [i for i in range(len(X)) if i not in nonlinear_svc.support_]
svc_all_without_rbf_support = SVC(kernel='rbf').fit(X[non_support_vectors, :], y[non_support_vectors])
plot_separating_surface(X, y, svc_all_without_rbf_support)
plot_separating_surface(X, y, nonlinear_svc)
plot_separating_surface(X, y, svc_on_rbf_support)
Сделайте вывод: Сильно ли полученные поверхности отличаются от той, что была получена в первом задании? Что произошло с пограничными объектами? Объясните полученные результаты.
**Ваши выводы тут:**
Результаты отличаются, но несильно. Разные модели имеют разную способность выражать нелинейные зависимости, вручную добавленные признаки помогают, но rbf-ядро делает это гораздо эффективнее и гибче.
Возможность строить нелинейные поверхности может сильно улучшить качество, но и несет риск переобучения. В этом задании предстоит обучить лучшую svm модель и получить хорошее качество на тесте в системе тестирования. Для контроля переобучения рекомендуется пользоваться кросс-валидацией. Для улучшения качества рекомендуется подбирать
Также не забывайте, что при решении задач машинного обучения полезно смотреть в данные :)
Все csv-таблицы с данными вы можете взять из публичного теста, который также есть в проверяющей системе. Для этого распакуйте архив с публичными тестами и положите файлы в рабочей директории (рядом с ноутбуком)
X_train = np.load('05-SVM/public/cX_train.npy')
y_train = np.load('05-SVM/public/cy_train.npy')
X_test = np.load('05-SVM/public/cX_test.npy')
X_train.shape, y_train.shape, X_test.shape
((800, 5), (800,), (200, 5))
X = X_train
y = y_train.ravel()
plt.scatter(X[y == 0, 4], X[y == 0, 3], label='y=0')
plt.scatter(X[y == 1, 4], X[y == 1, 3], label='y=1')
plt.legend()
<matplotlib.legend.Legend at 0x7b9582b26a80>
Отправьте код обучения модели с оптимальными параметрами в проверяющую систему, воспользовавшись приложенным шаблоном svm_solution.py. Кросс-валидацию параметров в посылаемом решении делать не нужно -- достаточно подобрать, например, их тут, а в решении уже обучать модель с оптимальными параметрами.
В предыдущей части Вы обучили хорошую SVM модель, подбирая гиперпараметры модели. Давайте теперь попробуем обучить логистическую регрессию на этой же выборке, и по кросс-валидации оценить влияние гиперпараметров на линейную модель.
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
pipe = Pipeline([
("scaler", StandardScaler()),
("logreg", LogisticRegression(max_iter=5000))
])
param_grid = {
"logreg__C": [0.01, 0.1, 1, 10],
}
grid = GridSearchCV(pipe, param_grid, cv=5, scoring="accuracy")
grid.fit(X, y)
print("Best params:", grid.best_params_)
print("CV accuracy:", grid.best_score_)
Best params: {'logreg__C': 1}
CV accuracy: 0.78125
Сделайте выводы о влиянии выбора гиперпараметров на качество обучения линейной и SVC моделей. Также опишите, какие преобразования выборки/подбор каких гиперпараметров помогли добиться высокого качества на кросс-валидации в данной задаче.
**Ваши выводы тут:**
Линейные модели ограничены формой решения и зависят в основном от регуляризации. SVM с rbf-ядром при правильном подборе гиперпараметров обеспечивает значительно лучшее качество благодаря возможности моделировать сложные, нелинейные разделяющие поверхности.
Найдите мем про SVM лучше чем этот:
Важно: самый простой способ вставить картинку будет через Google Colab (даже если вы изначально делали не в нем). Нажмите на "+ Text", в появившейся ячейке сделайте прикрепление картинки (как на скринах). Тогда ваша картинка "зашифруется" и будет корректно отображаться при конвертации в html